home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / PC100.C < prev    next >
C/C++ Source or Header  |  1996-12-28  |  14KB  |  510 lines

  1. #ifdef MSDOS
  2. /* Interface driver for the PACCOMM PC-100 board for the IBM PC */
  3. /* UNFINISHED, DOESN'T WORK YET - work in progress by Bdale */
  4. /* currently only attempting to use the AMD7910 on Channel A */
  5.  
  6. #include "global.h"
  7. #ifdef PC100
  8. #include <dos.h>
  9. #include "mbuf.h"
  10. #include "iface.h"
  11. #include "pktdrvr.h"
  12. #include "netuser.h"
  13. #include "pc100.h"
  14. #include "z8530.h"
  15. #include "ax25.h"
  16. #include "trace.h"
  17. #include "pc.h"
  18.  
  19. #if !defined(_lint)
  20. static char rcsid[] OPTIONAL = "$Id: pc100.c,v 1.12 1996/12/29 02:47:22 root Exp root $";
  21. #endif
  22.  
  23. static void hspint (struct hdlc *hp);
  24. static void hexint (struct hdlc *hp);
  25. static void hrxint (struct hdlc *hp);
  26. static void htxint (register struct hdlc *hp);
  27. static void rts (int16 base,int x);
  28. static void hdlcparam (struct hdlc *hp);
  29. static int pc_raw (struct iface *iface,struct mbuf *bp);
  30. static int pc_stop (struct iface *iface);
  31.  
  32. static struct pc100 Pc100[NPC];
  33. static void (*Pchandle[])() = { pc0vec };
  34. static struct hdlc Hdlc[2*NPC];
  35. static int16 Npc;
  36.  
  37. /* Branch table for interrupt handler */
  38. static void (*Svec[]) (struct hdlc *hp) = {
  39.     htxint, hexint, hrxint, hspint
  40. };
  41.  
  42. /* Master interrupt handler for the PC-100 card. All interrupts come
  43.  * here first, then are switched out to the appropriate routine.
  44.  */
  45. void
  46. pcint(dev)
  47. int dev;
  48. {
  49.     register char iv;
  50.     register int16 pcbase;
  51.     struct hdlc *hp;
  52.  
  53.     Pc100[dev].ints++;
  54.     pcbase = Pc100[dev].addr;
  55.  
  56.     /* Read interrupt vector, including status, from channel B */
  57.     iv = read_scc(CTL+pcbase+CHANB,R2);
  58.  
  59.     hp = &Hdlc[2 * dev + ((iv & 0x80)? 0 : 1)];
  60.  
  61.     /* Now switch to appropriate routine */
  62.     (*Svec[(iv>>1) & 0x3])(hp);
  63.  
  64.     /* Reset interrupt pending state (register A only) */
  65.     write_scc(CTL+pcbase+CHANA,R0,RES_H_IUS);
  66.  
  67.     /* Wang the 8530 hardware interrupt acknowledge line - Bdale */
  68.     inportb(pcbase+INTACK);
  69. }
  70. /* HDLC Special Receive Condition interrupt
  71.  * The most common event that triggers this interrupt is the
  72.  * end of a frame; it can also be caused by a receiver overflow.
  73.  */
  74. static void
  75. hspint(hp)
  76. register struct hdlc *hp;
  77. {
  78.     register char c;
  79.  
  80.     hp->spints++;
  81.     c = read_scc(CTL+hp->base,R1);    /* Fetch latched bits */
  82.  
  83.     if((c & (END_FR|CRC_ERR)) == END_FR && hp->rcvbuf != NULLBUF
  84.         && hp->rcvbuf->cnt > 1){
  85.         /* End of valid frame */
  86.         hp->rcvbuf->cnt--;    /* Toss 1st crc byte */
  87.         enqueue(&hp->rcvq,hp->rcvbuf);
  88.         hp->rcvbuf = NULLBUF;
  89.         hp->rcvcnt++;
  90.     } else {
  91.         /* An overflow or CRC error occurred; restart receiver */
  92.         hp->crcerr++;
  93.         if(hp->rcvbuf != NULLBUF){
  94.             hp->rcp = hp->rcvbuf->data;
  95.             hp->rcvbuf->cnt = 0;
  96.         }
  97.     }
  98.     write_scc(CTL+hp->base,R0,ERR_RES);
  99. }
  100. /* HDLC SIO External/Status interrupts
  101.  * The only one of direct interest is a receiver abort; the other
  102.  * usual cause is a change in the modem control leads, so kick the
  103.  * transmit interrupt routine.
  104.  */
  105. static void
  106. hexint(hp)
  107. register struct hdlc *hp;
  108. {
  109.     hp->exints++;
  110.     hp->status = read_scc(CTL+hp->base,R0);    /* Fetch status */
  111.     if((hp->status & BRK_ABRT) && hp->rcvbuf != NULLBUF){
  112.         hp->aborts++;
  113.         /* Restart receiver */
  114.         hp->rcp = hp->rcvbuf->data;
  115.         hp->rcvbuf->cnt = 0;
  116.     }
  117.     write_scc(CTL+hp->base,R0,RES_EXT_INT);
  118.     write_scc(CTL+hp->base,R0,RES_H_IUS);
  119.     /* Kick the transmit interrupt routine for a possible modem change */
  120.     htxint(hp);
  121. }
  122. /* HDLC receiver interrupt handler. Allocates buffers off the freelist,
  123.  * fills them with receive data, and puts them on the receive queue.
  124.  */
  125. static void
  126. hrxint(hp)
  127. register struct hdlc *hp;
  128. {
  129.     register struct mbuf *bp;
  130.     register int16 base;
  131.  
  132.     hp->rxints++;
  133.     base = hp->base;
  134.     /* Allocate a receive buffer if not already present */
  135.     if((bp = hp->rcvbuf) == NULLBUF){
  136.         bp = hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  137.         if(bp == NULLBUF){
  138.             /* No memory, abort receiver */
  139.             hp->nomem++;
  140.             write_scc(CTL+base,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  141.             (void) inportb(base+DATA);
  142.             return;
  143.         }
  144.         hp->rcp = hp->rcvbuf->data;
  145.     }
  146.     while(read_scc(CTL+base,R0) & Rx_CH_AV){
  147.         if(bp->cnt++ >= hp->bufsiz){
  148.             /* Too large; abort the receiver, toss buffer */
  149.             hp->toobig++;
  150.             write_scc(CTL+base,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  151.             (void) inportb(base+DATA);
  152.             free_p(bp);
  153.             hp->rcvbuf = NULLBUF;
  154.             break;
  155.         }
  156.         /* Normal save */
  157.         *hp->rcp++ = inportb(base+DATA);
  158.     }
  159. }
  160. static int ctswait;
  161. /* HDLC transmit interrupt service routine
  162.  *
  163.  * The state variable tstate, along with some static pointers,
  164.  * represents the state of the transmit "process".
  165.  */
  166. static void
  167. htxint(hp)
  168. register struct hdlc *hp;
  169. {
  170.     register int16 base;
  171.     char i_state;
  172.     int c;
  173.  
  174.     i_state = disable ();
  175.     hp->txints++;
  176.     base = hp->base;
  177.     while(read_scc(CTL+base,R0) & Tx_BUF_EMP){
  178.         switch(hp->tstate){
  179.         /* First here for efficiency */
  180.         case ACTIVE:        /* Sending frame */
  181.             if((c = PULLCHAR(&hp->sndbuf)) != -1){
  182.                 outportb(base+DATA,c);
  183.             } else {
  184.                 /* Do this after sending the last byte */
  185.                 write_scc(CTL+base,R0,RES_Tx_P);
  186.                 if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
  187.                     switch(hp->mode){
  188.                     case CSMA:
  189.                         /* Begin transmitter shutdown */
  190.                         hp->tstate = FLUSH;
  191.                         break;
  192.                     case FULLDUP:
  193.                         hp->tstate = IDLE;
  194.                         break;
  195.                     }
  196.                 }
  197.             }
  198.             continue;
  199.         case IDLE:
  200.             /* Transmitter idle. Find a frame for transmission */
  201.             if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF)
  202.                 goto ret;
  203.  
  204.         case DEFER:    /* note fall-thru */
  205.             if(hp->mode == CSMA && (hp->status & DCD)){
  206.                 hp->tstate = DEFER;
  207.                 goto ret;
  208.             }
  209.             rts(base,ON);    /* Transmitter on */
  210.         case KEYUP:    /* note fall-thru */
  211.             if((hp->status & CTS) == 0){
  212.                 ctswait++;
  213.                 hp->tstate = KEYUP;
  214.                 goto ret;
  215.             }
  216.             write_scc(CTL+base,R0,RES_Tx_CRC);
  217.             c = PULLCHAR(&hp->sndbuf);
  218.             outportb(hp->base+DATA,c);
  219.             hp->tstate = ACTIVE;
  220.             write_scc(CTL+base,R0,RES_EOM_L);
  221.             continue;
  222.         case FLUSH:    /* Sending flush character */
  223.             outportb(hp->base+DATA,(char)0);
  224.             hp->tstate = FIN2;
  225.             continue;
  226.         case FIN2:
  227.             write_scc(CTL+base,R0,SEND_ABORT);
  228.             hp->tstate = IDLE;
  229.             rts(base,OFF);
  230.             write_scc(CTL+base,R0,RES_Tx_P);
  231.             continue;
  232.         }
  233.     }
  234. ret:    restore(i_state);
  235. }
  236.  
  237. /* Set request-to-send on modem */
  238. static void
  239. rts(base,x)
  240. int16 base;
  241. int x;
  242. {
  243.     int16 cmd;
  244.  
  245.     if(x)
  246.         cmd = TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR;
  247.     else
  248.         cmd = TxCRC_ENAB | TxENAB | Tx8 | DTR;
  249.     write_scc(CTL+base,R5,cmd);
  250. }
  251. /* (re)Initialize HDLC controller parameters */
  252. static void
  253. hdlcparam(hp)
  254. register struct hdlc *hp;
  255. {
  256.     int16 tc;
  257.     char i_state;
  258.     register int16 base;
  259.  
  260.     /* Initialize 8530 channel for SDLC operation */
  261.     base = hp->base;
  262.     i_state = disable ();
  263.  
  264.     switch(base & 2){
  265.     case 0:
  266.         write_scc(CTL+base,R9,CHRA);    /* Reset channel A */
  267.         break;
  268.     case 2:
  269.         write_scc(CTL+base,R9,CHRB);    /* Reset channel B */
  270.         break;
  271.     }
  272.     /* Wait/DMA disable, Int on all Rx chars + spec condition,
  273.      * parity NOT spec condition, TxINT enable, Ext Int enable
  274.      */
  275.     write_scc(CTL+base,R1,INT_ALL_Rx | TxINT_ENAB | EXT_INT_ENAB);
  276.  
  277.     /* Dummy interrupt vector, will be modified by interrupt type
  278.      * (This probably isn't necessary)
  279.      */
  280.     write_scc(CTL+base,R2,0);
  281.  
  282.     /* 8 bit RX chars, auto enables off, no hunt mode, RxCRC enable,
  283.      * no address search, no inhibit sync chars, enable RX
  284.      */
  285.     write_scc(CTL+base,R3,Rx8|RxCRC_ENAB|RxENABLE);
  286.  
  287.     /* X1 clock, SDLC mode, Sync modes enable, parity disable
  288.      * (Note: the DPLL does a by-32 clock division, so it's not necessary
  289.      * to divide here).
  290.      */
  291.     write_scc(CTL+base,R4,X1CLK | SDLC | SYNC_ENAB);
  292.  
  293.     /* DTR On, 8 bit TX chars, no break, TX enable, SDLC CRC,
  294.      * RTS off, TxCRC enable
  295.      */
  296.     write_scc(CTL+base,R5,DTR|Tx8|TxENAB|TxCRC_ENAB);
  297.  
  298.     /* SDLC flag */
  299.     write_scc(CTL+base,R7,FLAG);
  300.  
  301.     /* No reset, status low, master int enable, enable lower chain,
  302.      * no vector, vector includes status
  303.      */
  304.     write_scc(CTL+base,R9,MIE|NV|VIS);
  305.     /* CRC preset 1, NRZI encoding, no active on poll, flag idle,
  306.      * flag on underrun, no loop mode, 8 bit sync
  307.      */
  308.     write_scc(CTL+base,R10,CRCPS|NRZI);
  309.  
  310.     /* Board no longer channel-specific for clk.  The board should be set
  311.      * up to run from the 4.9152Mhz onboard crystal connected to PCLK.
  312.      * Both channels get receive clock at 32x from PCLK via the DPLL,
  313.      * with TRxC as an output, via a 4040 div by 32 counter to RTxC set
  314.      * us as an input to provide the transmit clock.
  315.      */
  316.  
  317.     /*            TRxC = BR Generator Output, TRxC O/I,
  318.      *          transmit clock = RTxC pin, 
  319.      *          receive clock = DPLL output
  320.      */
  321.     write_scc(CTL+base,R11,TRxCBR|TRxCOI|TCRTxCP|RCDPLL);
  322.  
  323.     /* Compute and load baud rate generator time constant
  324.      * DPLL needs x32 clock
  325.      * XTAL is defined in pc100.h to be the crystal clock / (2 * 32)
  326.      */
  327.     tc = XTAL/(hp->speed) - 2;
  328.     write_scc(CTL+base,R12,tc & 0xff);
  329.     write_scc(CTL+base,R13,(tc >> 8) & 0xff);
  330.  
  331.     write_scc(CTL+base,R14,SNRZI);    /* Set NRZI mode */
  332.     write_scc(CTL+base,R14,SSBR);    /* Set DPLL source = BR generator */
  333.     write_scc(CTL+base,R14,SEARCH);    /* Enter search mode */
  334.     /* Set baud rate gen source = PCLK, enable baud rate gen */
  335.     write_scc(CTL+base,R14,BRENABL|BRSRC);
  336.  
  337.     /* Break/abort IE, TX EOM IE, CTS IE, no SYNC/HUNT IE, DCD IE,
  338.      * no Zero Count IE
  339.      */
  340.     write_scc(CTL+base,R15,BRKIE|TxUIE|CTSIE|DCDIE);
  341.  
  342.     restore(i_state);
  343.     if(hp->mode == FULLDUP){
  344.         rts(base,ON);
  345.     } else if(hp->tstate == IDLE){
  346.         rts(base,OFF);
  347.     }
  348. }
  349. /* Attach a PC-100 interface to the system
  350.  * argv[0]: hardware type, must be "pc100"
  351.  * argv[1]: I/O address, e.g., "0x380"
  352.  * argv[2]: vector, e.g., "2"
  353.  * argv[3]: mode, must be:
  354.  *        "ax25" (AX.25 UI frame format)
  355.  * argv[4]: interface label, e.g., "pc0"
  356.  * argv[5]: receiver packet buffer size in bytes
  357.  * argv[6]: maximum transmission unit, bytes
  358.  * argv[7]: interface speed, e.g, "9600"
  359.  * argv[8]: First IP address, optional (defaults to Ip_addr)
  360.  * argv[9]: Second IP address, optional (defaults to Ip_addr)
  361.  */
  362. int
  363. pc_attach(argc,argv,p)
  364. int argc;
  365. char *argv[];
  366. void *p;
  367. {
  368.     register struct iface *if_pca,*if_pcb;
  369.     struct hdlc *hp;
  370.     int dev;
  371.  
  372.     if(Npc >= NPC){
  373.         tputs("Too many pc100 controllers\n");
  374.         return -1;
  375.     }
  376.     if(if_lookup(argv[4]) != NULLIF){
  377.         tprintf(Existingiface,argv[4]);
  378.         return -1;
  379.     }
  380.     dev = Npc++;
  381.  
  382.     /* Initialize hardware-level control structure */
  383.     Pc100[dev].addr = htoi(argv[1]);
  384.     Pc100[dev].vec = htoi(argv[2]);
  385.     /* Initialize modems */
  386.     outportb(Pc100[dev].addr + MODEM_CTL,(char)0x22);
  387.  
  388.     /* Save original interrupt vector */
  389.     Pc100[dev].oldvec = getirq(Pc100[dev].vec);
  390.     /* Set new interrupt vector */
  391.     if(setirq(Pc100[dev].vec,Pchandle[dev]) == -1){
  392.         tprintf("IRQ %u out of range\n",Pc100[dev].vec);
  393.         Npc--;
  394.         return -1;
  395.     }
  396.     /* Create interface structures and fill in details */
  397.     if_pca = (struct iface *)callocw(1,sizeof(struct iface));
  398.     if_pcb = (struct iface *)callocw(1,sizeof(struct iface));
  399.  
  400.     if_pca->addr = if_pcb->addr = Ip_addr;
  401.     if(argc > 8)
  402.         if_pca->addr = resolve(argv[8]);
  403.  
  404.     if(argc > 9)
  405.         if_pcb->addr = resolve(argv[9]);
  406.     if(if_pca->addr == 0 || if_pcb->addr == 0){
  407.         tputs(Noipaddr);
  408.         free((char *)if_pca);
  409.         free((char *)if_pcb);
  410.         return -1;
  411.     }
  412.     if_pca->name = strdup(argv[4]);
  413.     argv[4][strlen(argv[4]) - 1]++;
  414.     if_pcb->name = strdup(argv[4]);
  415.     argv[4][strlen(argv[4]) - 1]--;
  416.     if_pcb->mtu = if_pca->mtu = atoi(argv[6]);
  417.     if_pcb->type = if_pca->type = CL_AX25;
  418.     if_pca->dev = 2*dev;
  419.     if_pcb->dev = 2*dev + 1;
  420.     if_pcb->stop = if_pca->stop = pc_stop;
  421.     if_pcb->output = if_pca->output = ax_output;
  422.     if_pcb->raw = pc_raw;
  423.     if_pcb->iface_metric = if_pca->iface_metric = 1;
  424.  
  425.     if(strcmp(argv[3],"ax25") == 0){
  426.         if(Mycall[0] == '\0'){
  427.             tputs("set mycall first\n");
  428.             free((char *)if_pca);
  429.             free((char *)if_pcb);
  430.             return -1;
  431.         }        
  432.         if_pcb->send = if_pca->send = ax_send;
  433.         if(if_pcb->hwaddr == NULLCHAR)
  434.             if_pcb->hwaddr = mallocw(AXALEN);
  435.         memcpy(if_pcb->hwaddr,Mycall,AXALEN);
  436.         if(if_pcb->ipcall == NULLCHAR)
  437.             if_pcb->ipcall = mallocw(AXALEN);
  438.         memcpy(if_pcb->ipcall,Mycall,AXALEN);
  439.     } else {
  440.         tprintf("Mode %s unknown for interface %s\n",
  441.             argv[3],argv[4]);
  442.         free((char *)if_pca);
  443.         free((char *)if_pcb);
  444.         return -1;
  445.     }
  446.     if_pca->next = if_pcb;
  447.     if_pcb->next = Ifaces;
  448.     Ifaces = if_pca;
  449.  
  450.     hp = &Hdlc[2*dev+1];
  451.     hp->speed = (int16)atoi(argv[7]);
  452.     hp->base = Pc100[dev].addr + CHANB;
  453.     hp->bufsiz = atoi(argv[5]);
  454.     hdlcparam(hp);
  455.  
  456.     hp = &Hdlc[2*dev];
  457.     hp->speed = (int16)atoi(argv[7]);
  458.     hp->base = Pc100[dev].addr + CHANA;
  459.     hp->bufsiz = atoi(argv[5]);
  460.     hdlcparam(hp);
  461.  
  462.     /* Clear mask (enable interrupt) in 8259 interrupt controller */
  463.     clrbit(INTMASK,(char)(1<<Pc100[dev].vec));
  464.  
  465.     return 0;
  466. }
  467. static int
  468. pc_stop(iface)
  469. struct iface *iface;
  470. {
  471.     int dev;
  472.  
  473.     dev = iface->dev;
  474.     if(dev & 1)
  475.         return 0;
  476.     dev >>= 1;    /* Convert back into PC100 number */
  477.     /* Turn off interrupts */
  478.     maskoff(Pc100[dev].vec);
  479.  
  480.     /* Restore original interrupt vector */
  481.     setirq(Pc100[dev].vec,Pc100[dev].oldvec);
  482.  
  483.     /* Force hardware reset */
  484.     write_scc(CTL+Pc100[dev].addr + CHANA,R9,FHWRES);
  485.     return 0;
  486. }
  487.     
  488. /* Send raw packet on PC-100 */
  489. static int
  490. pc_raw(iface,bp)
  491. struct iface *iface;
  492. struct mbuf *bp;
  493. {
  494.     char kickflag;
  495.     struct hdlc *hp;
  496.  
  497.     dump(iface,IF_TRACE_OUT,CL_AX25,bp);
  498.     iface->rawsndcnt++;
  499.     iface->lastsent = secclock();
  500.     hp = &Hdlc[iface->dev];
  501.     kickflag = (hp->sndq == NULL);
  502.     enqueue(&hp->sndq,bp);
  503.     if(kickflag)
  504.         htxint(&Hdlc[iface->dev]);
  505.     return 0;
  506. }
  507. #endif /* PC100 */
  508. #endif /* MSDOS */
  509.  
  510.